package com.deimos.sps;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.axiom.om.OMElement;
import org.vast.cdm.common.CDMException;
import org.vast.cdm.common.DataComponent;
import org.vast.ows.OWSException;
import org.vast.ows.OWSResponse;
import org.vast.ows.sps.FeasibilityReport;
import org.vast.ows.sps.GetFeasibilityResponse;
import org.vast.ows.sps.ReservationReport;
import org.vast.ows.sps.ReserveRequest;
import org.vast.ows.sps.StatusReport;
import org.vast.ows.sps.SubmitResponse;
import org.vast.ows.sps.TaskingRequest;
import org.vast.ows.sps.TaskingResponse;
import org.vast.ows.sps.StatusReport.RequestStatus;
import org.vast.ows.sps.StatusReport.TaskStatus;
import org.vast.util.DateTime;
import org.vast.xml.DOMHelperException;

import com.deimos.Notification;
import com.deimos.UtilsDeimos;
import com.deimos.dataBase.Event;
import com.deimos.dataBase.Scenario;
import com.deimos.dataBase.ScenarioResponse;
import com.deimos.dataBase.Segment;
import com.deimos.dataBase.Sensor;
import com.deimos.dataBase.Task;
import com.deimos.dataBase.TaskController;
import com.deimos_space.sps_cfi.jni.Feasibility;
import com.deimos_space.sps_cfi.jni.FeasibilityStudy;
import com.deimos_space.sps_cfi.jni.Planner;
import com.spotimage.eosps.EOOpticalParamHelper;
import com.spotimage.eosps.EOParamHelper;
import com.spotimage.eosps.EORadarParamHelper;
import com.spotimage.eosps.EOReportHelper;
import com.spotimage.eosps.EOConstants.AcqStatus;
import com.spotimage.eosps.EOConstants.FeasibilityLevel;
import com.spotimage.eosps.EOConstants.InformationType;
import com.spotimage.eosps.EOConstants.ReportType;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;

public class GetFeasibility extends Thread {

	public enum Operation {
		STUDIED, UPDATED, RESERVED, SUBMITTED, CONFIRMED
	}

	protected TaskingRequest request = null;
	private String taskID = null;
	protected Set<Segment> segments;
	protected String updateTask = null;
	protected String referencedId = null;
	private Operation operation = null;
	protected Sensor sensor = null;

	private FeasibilityStudy fsResult = null;
	private Planner planner = null;

	boolean allowGetFeasibility = true;

	private TaskingResponse<StatusReport> tkResponse = null;

	public static final long WAIT = 0;

	public static String DATE_FORMAT_CFI = "yyyy-MM-dd'_'HH:mm:ss.SSSSSS";
	public static String DATE_FORMAT_HMA = "yyyy-MM-dd'T'HH:mm:ss'Z'";

	public static SimpleDateFormat sdf_cfi = new SimpleDateFormat(
			DATE_FORMAT_CFI);
	public static SimpleDateFormat sdf_hma = new SimpleDateFormat(
			DATE_FORMAT_HMA);

	private String instrumentMode, polarizationMode;
	double[] regionOfInterest_lat, regionOfInterest_lon,
			elevationIncidenceAngle;
	String[] surveyPeriod;
	FeasibilityLevel level;

	DateTime begin, end;
	double minRange, maxRange, maxCloud = -1;
	int occurrences;

	TaskController taskController = new TaskController();
	protected String percentage = "";
	private ScenarioResponse acquisitionSuccess;
	private boolean cfi_error = true;
	private static boolean messages = true;

	public GetFeasibility() {
		GetFeasibility.enableMessages(messages);
	}

	public GetFeasibility(TaskingRequest request, Sensor sensor)
			throws ParseException, OWSException {
		init(request, null, Operation.STUDIED, sensor, null);
	}

	public GetFeasibility(TaskingRequest request, String taskID,
			Operation operation, Sensor sensor) throws ParseException,
			OWSException {
		init(request, taskID, operation, sensor, null);
	}

	public void init(TaskingRequest request, String taskID,
			Operation operation, Sensor sensor, DataComponent taskingParams)
			throws ParseException, OWSException {
		try {
			EOParamHelper rpHelper = null;
			this.sensor = sensor;
			this.request = request;
			this.operation = operation;

			if (taskingParams == null && sensor.getType().compareTo("OPT") == 0)
				rpHelper = new EOOpticalParamHelper(this.request);
			else if (taskingParams == null)
				rpHelper = new EORadarParamHelper(this.request);
			else if (sensor.getType().compareTo("OPT") == 0)
				rpHelper = new EOOpticalParamHelper(this.request, taskingParams);
			else
				rpHelper = new EORadarParamHelper(this.request, taskingParams);

			referencedId = rpHelper.getReferenceFeasibilityID();
			if (sensor.getType().compareTo("OPT") == 0)
				try {
					maxCloud = ((EOOpticalParamHelper) rpHelper)
							.getMaxCloudCover();
				} catch (Exception ex) {
					maxCloud = 100;
				}
			else
				polarizationMode = ((EORadarParamHelper) rpHelper)
						.getPolarizationMode();

			// obtain parameter values
			Polygon roi = rpHelper.getPolygonROI();

			begin = new DateTime(rpHelper.getSurveyStartDate());
			end = new DateTime(rpHelper.getSurveyEndDate());

			double minElevIncidence = rpHelper.getMinElevationIncidence();
			double maxElevIncidence = rpHelper.getMaxElevationIncidence();

			Coordinate[] roiCoordinates = roi.getCoordinates();

			//
			// Parameter for SkyWalker constructor
			//
			regionOfInterest_lat = new double[roiCoordinates.length - 1];
			regionOfInterest_lon = new double[roiCoordinates.length - 1];
			surveyPeriod = new String[2];
			elevationIncidenceAngle = new double[2];
			instrumentMode = rpHelper.getInstrumentMode();

			// Calculate coordinates
			for (int i = 0; i < roiCoordinates.length - 1; i++) {
				regionOfInterest_lat[i] = roiCoordinates[i].y;
				regionOfInterest_lon[i] = roiCoordinates[i].x;
			}

			surveyPeriod[0] = sdf_cfi.format(begin);
			surveyPeriod[1] = sdf_cfi.format(end);

			maxRange = rpHelper.getMaxTimeSeriesPeriodicity();
			minRange = rpHelper.getMinTimeSeriesPeriodicity();
			occurrences = rpHelper.getTimeSeriesOccurences();

			elevationIncidenceAngle[0] = minElevIncidence;
			elevationIncidenceAngle[1] = maxElevIncidence;

			updateTask = taskID;
			referencedId = rpHelper.getReferenceFeasibilityID();
			// rpHelper.getPriorityLevel()

			this.taskID = Planner.getNewFeasibilityId();
			level = rpHelper.getFeasibilityLevel();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			if (e.getMessage().contains("FeasibilityLevel")) {
				throw new OWSException(OWSException.invalid_param_code,
						"FeasibilityLevel");
			}
			if (e.getMessage().contains("points")) {
				throw new OWSException(OWSException.invalid_param_code,
						"RegionOfInterest", e.getMessage());
			}
		}

		if (occurrences > 0 && minRange != 0) {
			long x = occurrences * ((long) minRange * 24 * 60 * 60 * 1000);
			Date maxDate = new Date(sdf_cfi.parse(this.surveyPeriod[0])
					.getTime()
					+ x);
			if (sdf_cfi.parse(this.surveyPeriod[1]).before(maxDate)) {
				throw new OWSException(OWSException.invalid_param_code,
						"TimeOfInterest");
			}
		}

	}

	@SuppressWarnings("unchecked")
	private void buildResponse() throws OWSException {
		try {
			if (Operation.STUDIED == operation) {
				tkResponse = (TaskingResponse<StatusReport>) Class.forName(
						"org.vast.ows.sps.GetFeasibilityResponse")
						.newInstance();
				tkResponse.setVersion("2.0.0");
				tkResponse.setReport(new FeasibilityReport());
				tkResponse.getReport().setTitle("CFI based Feasibility Study");
			} else if (Operation.UPDATED == operation) {
				tkResponse = (TaskingResponse<StatusReport>) Class.forName(
						"org.vast.ows.sps.UpdateResponse").newInstance();
				tkResponse.setVersion("2.0.0");
				tkResponse.setReport(new FeasibilityReport());
				tkResponse.getReport().setTitle("CFI based Update Request");
			} else if (Operation.RESERVED == operation) {
				tkResponse = (TaskingResponse<StatusReport>) Class.forName(
						"org.vast.ows.sps.ReserveResponse").newInstance();
				tkResponse.setVersion("2.0.0");
				tkResponse.setReport(new ReservationReport());
				tkResponse.getReport().setTitle("CFI based Reserve Request");
			} else if (Operation.SUBMITTED == operation) {
				tkResponse = new SubmitResponse(); // (TaskingResponse<StatusReport>)
				// Class.forName("org.vast.ows.sps.SubmitResponse").newInstance();
				tkResponse.setVersion("2.0.0");
				tkResponse.setReport(new StatusReport());
				tkResponse.getReport().setTitle("CFI based Submit Request");
			}

			tkResponse.getReport().setTaskID(taskID);
			tkResponse.getReport().setSensorID(request.getSensorID());
			tkResponse.getReport().setRequestStatus(RequestStatus.Accepted);
			tkResponse.getReport().setLastUpdate(new DateTime());
			tkResponse.getReport().setEstimatedDelay(300);
			// tkResponse.getReport().setEstimatedToC(toc);

			DateTime toc = null;
			if (this.referencedId != null
					&& taskController.getLastEvent(this.referencedId) != null) {
				if (operation == Operation.RESERVED)
					((ReserveRequest) request).setReservationExpiration(null);
				if (Event.compare(
						taskController.getLastEvent(this.referencedId)
								.getRequestParameters(), UtilsDeimos
								.getParameters(request))
						&& taskController.getLastEvent(this.referencedId)
								.getRequestParameters().contains(
										"GetFeasibility")) {
					Date expiration = new DateTime(taskController.getLastEvent(
							this.referencedId).getResponseParameters().split(
							"expirationDate>")[1].split("<")[0]);
					GetFeasibilityResponse lastResponse = (GetFeasibilityResponse) UtilsDeimos
							.readParams(taskController.getLastEvent(
									this.referencedId).getResponseParameters());
					if (lastResponse.getReport().getRequestStatus() != RequestStatus.Accepted) {
						throw new OWSException(OWSException.invalid_param_code,
								"ReferenceFeasibilityID",
								"The referenced feasibility study was not accepted");
					}
					if (expiration.before(new Date())) {
						throw new OWSException(OWSException.invalid_param_code,
								"ReferenceFeasibilityID",
								"The referenced feasibility study is expired");
					}
					UtilsDeimos.feasibilityStudyToProgress(lastResponse
							.getReport(), operation, sensor);
					if (operation == Operation.RESERVED)
						tkResponse
								.setReport(UtilsDeimos
										.getReservationReport(lastResponse
												.getReport()));
					else
						tkResponse.setReport(lastResponse.getReport());
					tkResponse.getReport().touch();
					List<String> tasks = taskController.isSensorInUse(request
							.getSensorID(), operation, tkResponse);
					if (tasks != null && tasks.size() != 0) {
						String desc = "Task not feasible. The sensor "
								+ request.getSensorID() + " is in use by the ";
						if (tasks.size() > 1)
							desc = desc + "tasks: ";
						else
							desc = desc + "task: ";
						for (String task : tasks)
							desc = desc + task + ", ";
						desc = (desc + ".").replace(", .", ". ");
						tkResponse.getReport().setDescription(desc);
						tkResponse.getReport().setRequestStatus(
								RequestStatus.Rejected);
						tkResponse.getReport().setEstimatedToC(null);
						tkResponse.getReport().setPercentCompletion(Float.NaN);
						tkResponse.getReport().getExtensions().clear();

						tkResponse.getReport().touch();
						return;
					}
					EOReportHelper eohelper = new EOReportHelper(tkResponse,
							ReportType.PROG_STATUS);
					segments = new HashSet<Segment>();
					for (int s = 0; s < eohelper.getNumSegments(); s++) {
						eohelper.loadSegment(s);
						Segment segment = new Segment();
						segment.setName(eohelper.getID());
						segment.setBeginDate(eohelper.getAcquisitionStart());
						segment.setEndDate(eohelper.getAcquisitionStop());
						segment.setUpdateDate(new Date());
						segment.setSensor(sensor.getSensorId());
						segment.setAcqStatus(eohelper.getObjectStatus());
						segments.add(segment);
					}
					tkResponse.getReport().setTaskID(taskID);
					tkResponse.getReport().setLastUpdate(new DateTime());
					tkResponse.getReport().setEstimatedDelay(300);

					return;
				} else if (taskController.getLastEvent(this.referencedId)
						.getRequestParameters().contains("GetFeasibility")) {
					throw new OWSException(OWSException.invalid_request_code,
							"ReferenceFeasibilityID",
							"The referenced feasibility study must contain the same tasking parameters");
				}
			} else if (this.referencedId != null) {
				throw new OWSException(OWSException.invalid_param_code,
						"ReferenceFeasibilityID",
						"The referenced feasibility study does not exist");
			}

			if (cfi_error && !this.isAlive()) {
				tkResponse.getReport().setRequestStatus(RequestStatus.Rejected);
				tkResponse.getReport().setDescription(
						"CFI Library can not be loaded");
				tkResponse.getReport().setPercentCompletion(0);
				/*
				 * eohelper.setExpirationDelay(0); eohelper.setNumSegments(0);
				 * if (level != null && level == FeasibilityLevel.COMPLETE) {
				 * eohelper.addInformationUsed(InformationType.KINEMATIC_MODEL);
				 * eohelper
				 * .addInformationUsed(InformationType.ESTIMATED_WORKLOAD);
				 * eohelper.addInformationUsed(InformationType.REAL_WORKLOAD);
				 * if (Scenario.isScenarioEnabled())
				 * eohelper.addInformationUsed(
				 * InformationType.WEATHER_FORECAST); } else if (level == null
				 * || level == FeasibilityLevel.SIMPLE) {
				 * eohelper.addInformationUsed(InformationType.KINEMATIC_MODEL);
				 * eohelper
				 * .addInformationUsed(InformationType.ESTIMATED_WORKLOAD); if
				 * (Scenario.isScenarioEnabled())
				 * eohelper.addInformationUsed(InformationType
				 * .WEATHER_FORECAST); } eohelper.setEstimatedCost(0.0);
				 */

			} else if (fsResult == null) {
				tkResponse.getReport().setRequestStatus(RequestStatus.Pending);
				tkResponse.getReport().setDescription(
						"Task waiting for feasible study");
				tkResponse.getReport().setPercentCompletion(0);
				/*
				 * eohelper.setExpirationDelay(0); eohelper.setNumSegments(0);
				 * if (level != null && level == FeasibilityLevel.COMPLETE) {
				 * eohelper.addInformationUsed(InformationType.KINEMATIC_MODEL);
				 * eohelper
				 * .addInformationUsed(InformationType.ESTIMATED_WORKLOAD);
				 * eohelper.addInformationUsed(InformationType.REAL_WORKLOAD);
				 * if (Scenario.isScenarioEnabled())
				 * eohelper.addInformationUsed(
				 * InformationType.WEATHER_FORECAST); } else if (level == null
				 * || level == FeasibilityLevel.SIMPLE) {
				 * eohelper.addInformationUsed(InformationType.KINEMATIC_MODEL);
				 * eohelper
				 * .addInformationUsed(InformationType.ESTIMATED_WORKLOAD); if
				 * (Scenario.isScenarioEnabled())
				 * eohelper.addInformationUsed(InformationType
				 * .WEATHER_FORECAST); } eohelper.setEstimatedCost(0.0);
				 */

			} else if (fsResult.getResult().compareTo(Feasibility.NOT_FEASIBLE) == 0) {
				tkResponse.getReport().setRequestStatus(RequestStatus.Rejected);
				tkResponse.getReport()
						.setDescription(fsResult.getDescription());
				/*
				 * if (Operation.STUDIED == operation || !sensor.isSyn())
				 * eohelper.setExpirationDelay(24 * 3600);
				 * eohelper.setNumSegments(0);
				 * tkResponse.getReport().setPercentCompletion(0); if (level !=
				 * null && level == FeasibilityLevel.COMPLETE &&
				 * (Operation.STUDIED == operation || !sensor.isSyn())) {
				 * eohelper.addInformationUsed(InformationType.KINEMATIC_MODEL);
				 * eohelper
				 * .addInformationUsed(InformationType.ESTIMATED_WORKLOAD);
				 * eohelper.addInformationUsed(InformationType.REAL_WORKLOAD);
				 * if (Scenario.isScenarioEnabled())
				 * eohelper.addInformationUsed(
				 * InformationType.WEATHER_FORECAST); } else if ((level == null
				 * || level == FeasibilityLevel.SIMPLE) && (Operation.STUDIED ==
				 * operation || !sensor.isSyn())) {
				 * eohelper.addInformationUsed(InformationType.KINEMATIC_MODEL);
				 * eohelper
				 * .addInformationUsed(InformationType.ESTIMATED_WORKLOAD); if
				 * (Scenario.isScenarioEnabled())
				 * eohelper.addInformationUsed(InformationType
				 * .WEATHER_FORECAST); } if (Operation.STUDIED == operation ||
				 * !sensor.isSyn()) eohelper.setEstimatedCost(0.0);
				 */

			} else if (fsResult.getResult().compareTo(Feasibility.FEASIBLE) == 0) {

				segments = new HashSet<Segment>();
				tkResponse.getReport().setRequestStatus(RequestStatus.Accepted);
				tkResponse.getReport()
						.setDescription(fsResult.getDescription());
				tkResponse.getReport().setPercentCompletion(0);
				Scenario.setTimes(fsResult, begin, end);
				EOReportHelper eohelper;
				if (Operation.STUDIED == operation || !sensor.isSyn())
					eohelper = new EOReportHelper(tkResponse,
							ReportType.FEASIBILITY);
				else
					eohelper = new EOReportHelper(tkResponse,
							ReportType.PROG_STATUS);
				if (Operation.STUDIED == operation || !sensor.isSyn())
					eohelper.setEstimatedCost(0.0);
				if (level != null && level == FeasibilityLevel.COMPLETE
						&& (Operation.STUDIED == operation || !sensor.isSyn())) {
					eohelper
							.addInformationUsed(InformationType.KINEMATIC_MODEL);
					eohelper
							.addInformationUsed(InformationType.ESTIMATED_WORKLOAD);
					eohelper.addInformationUsed(InformationType.REAL_WORKLOAD);
					if (Scenario.isScenarioEnabled())
						eohelper
								.addInformationUsed(InformationType.WEATHER_FORECAST);
				} else if ((level == null || level == FeasibilityLevel.SIMPLE)
						&& (Operation.STUDIED == operation || !sensor.isSyn())) {
					eohelper
							.addInformationUsed(InformationType.KINEMATIC_MODEL);
					eohelper
							.addInformationUsed(InformationType.ESTIMATED_WORKLOAD);
					if (Scenario.isScenarioEnabled())
						eohelper
								.addInformationUsed(InformationType.WEATHER_FORECAST);
				}
				if (Operation.STUDIED == operation || !sensor.isSyn()) {
					eohelper.setExpirationDelay(24 * 3600);
					eohelper.setOverallSuccessRate((100 - fsResult
							.getWeatherChance()) / 100);
				}

				eohelper.setNumSegments(fsResult.getNbSwaths());
				for (int s = 0; s < fsResult.getNbSwaths(); s++) {

					eohelper.loadSegment(s);
					eohelper.setID("SEG_00" + (s + 1));

					if (Operation.STUDIED == operation || !sensor.isSyn())
						eohelper.setObjectStatus(AcqStatus.POTENTIAL);
					else
						eohelper.setObjectStatus(AcqStatus.PLANNED);
					eohelper.setPlatformID(sensor.platformId);
					eohelper.setPlatformName(sensor.platformName);
					eohelper.setInstrumentName(sensor.instrumentName);
					eohelper.setInstrumentMode(planner.getInstrumentMode());

					String[] segmentStartStop = fsResult.getSegments().get(s);

					Date segmentStart = sdf_cfi.parse(segmentStartStop[0]);
					Date segmentStop = sdf_cfi.parse(segmentStartStop[1]);

					if (Operation.STUDIED == operation || !sensor.isSyn())
						eohelper.setExpirationDate(new DateTime(segmentStop
								.getTime()));
					// Start/Stop times
					eohelper.setAcquisitionStart(new DateTime(sdf_hma
							.format(segmentStart)));
					eohelper.setAcquisitionStop(new DateTime(sdf_hma
							.format(segmentStop))); // ROI
					// eohelper.setElevationIncidence(5.5 + s/10.0);

					GeometryFactory fac = new GeometryFactory();
					// Swaths are rectangles. But we need 5 points because
					// function createLinearRing needs a closed linestring. The
					// 5th
					// and 1st point are the same.
					Coordinate[] swathCoordinates = new Coordinate[5];
					double[][] swathForMapping = fsResult.getSwaths().get(s);
					swathCoordinates[0] = new Coordinate(swathForMapping[0][0],
							swathForMapping[0][1]);
					swathCoordinates[1] = new Coordinate(swathForMapping[1][0],
							swathForMapping[1][1]);
					swathCoordinates[2] = new Coordinate(swathForMapping[2][0],
							swathForMapping[2][1]);
					swathCoordinates[3] = new Coordinate(swathForMapping[3][0],
							swathForMapping[3][1]);
					// We repeat the 1st point to close the rectangle
					swathCoordinates[4] = new Coordinate(swathForMapping[0][0],
							swathForMapping[0][1]);
					LinearRing outer = fac.createLinearRing(swathCoordinates);
					eohelper.setFootprint(fac.createPolygon(outer, null));

					eohelper.setNumGridCells(0);

					Segment segment = new Segment();
					segment.setName(eohelper.getID());
					segment.setBeginDate(segmentStart);
					segment
							.setEndDate(new DateTime(sdf_hma
									.format(segmentStop)));
					segment.setUpdateDate(new Date());
					segment.setSensor(sensor.getSensorId());
					segment.setAcqStatus(eohelper.getObjectStatus());
					segments.add(segment);
					if (messages)
						System.out.println(fac.createPolygon(outer, null)
								.toText());

				}
				toc = eohelper.getAcquisitionStop();

				// acquisitionSuccess = fsResult.getAcquisitionSuccess();

				acquisitionSuccess = Scenario.getAvailability(eohelper,
						tkResponse.getReport(), maxCloud);
				if (!acquisitionSuccess.isAvailable()) {
					for (int s = 0; s < fsResult.getNbSwaths(); s++) {
						eohelper.loadSegment(s);
						if (acquisitionSuccess.getSegments().contains(
								eohelper.getID()))
							eohelper.setObjectStatus(AcqStatus.REJECTED);
						else
							eohelper.setObjectStatus(AcqStatus.POTENTIAL);
					}
					tkResponse.getReport().setRequestStatus(
							RequestStatus.Rejected);
					tkResponse.getReport().setDescription(
							"Task not Feasible. "
									+ acquisitionSuccess.getDescription());
				} else {
					tkResponse.getReport().setRequestStatus(
							RequestStatus.Accepted);
					tkResponse.getReport().setDescription(
							"Task feasible. "
									+ acquisitionSuccess.getDescription());
				}
				eohelper.writeReportInfo();
				tkResponse.getReport().touch();
			}
			tkResponse.getReport().setEstimatedToC(toc);

		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (DOMHelperException e) {
			e.printStackTrace();
		}
	}

	public void run() {
		FeasibilityStudy fsResulttemp = null;
		if (!allowGetFeasibility)
			return;
		try {
			if (messages) {
				System.out.println("------------------------");
				System.out.println("Feasibility Study Started");
				System.out.println("------------------------");
			}
			planner = new Planner();
			planner.initPlanner(sensor, regionOfInterest_lat,
					regionOfInterest_lon, surveyPeriod,
					elevationIncidenceAngle, instrumentMode, polarizationMode,
					maxRange, minRange, occurrences, updateTask);
			planner.enableMessages(messages);
			if (this.referencedId == null)
				fsResulttemp = planner.studyFeasibility(true);
			cfi_error = false;
			Thread.sleep(sensor.study_delay);
			fsResult = fsResulttemp;
			if (messages) {
				System.out.println("------------------------");
				System.out.println("Feasibility Study Ended");
				System.out.println("------------------------");
			}
			if (!sensor.isSyn())
				updateStudyStatus();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public OWSResponse getResponse() throws OWSException {
		buildResponse();
		return tkResponse;
	}

	private void updateStudyStatus() throws CDMException, OWSException {

		if (operation == null)
			return;
		buildResponse();
		TaskController taskController = new TaskController();
		RequestStatus requestStatus = tkResponse.getReport().getRequestStatus();
		Event event = taskController.getLastEvent(this.taskID);
		if (event == null)
			return;

		taskController.validateStatus(taskID);

		if (event.getRequestStatus() == RequestStatus.Pending) {
			if (requestStatus == RequestStatus.Accepted) {
				event.setAcquisitionSuccessDescription(acquisitionSuccess
						.getDescription());
				event.setAcquisitionSuccess(acquisitionSuccess.isAvailable());
				event.setOperation(operation);
				// TASK UPDATED
				if (operation == Operation.UPDATED) {
					event.setEstimatedToC(tkResponse.getReport()
							.getEstimatedToC());
					event.setUpdateDate(new DateTime());
					event.setEventId(null);
					event
							.setDescription("Task updated successfully. Ref Task: "
									+ this.updateTask
									+ ". "
									+ tkResponse.getReport().getDescription());
					if (messages)
						System.out.println(event.getDescription());
					event.setRequestStatus(RequestStatus.Accepted);
					event.setResponseParameters(UtilsDeimos
							.getParameters(tkResponse));
					taskController.insertEvent(event);
					event
							.setDescription("Task updated successfully. Ref Task: "
									+ this.taskID
									+ ". "
									+ tkResponse.getReport().getDescription());
					event.setTask(taskController.getTask(this.updateTask));
					event.setEventId(null);
					Notification.notifyReport(event);
					taskController.insertEvent(event);
					taskController.insertSegments(segments, event.getTask());
				}

				// TASK SUBMITTED
				if (operation == Operation.SUBMITTED) {
					event.setEstimatedToC(tkResponse.getReport()
							.getEstimatedToC());
					event.setUpdateDate(new DateTime());
					event.setEventId(null);
					event.setDescription("Task submitted successfully. "
							+ tkResponse.getReport().getDescription());
					if (messages)
						System.out.println(event.getDescription());
					event.setResponseParameters(UtilsDeimos
							.getParameters(tkResponse));
					event.setRequestStatus(RequestStatus.Accepted);
					Notification.notifyReport(event);
					taskController.insertEvent(event);
					taskController.insertSegments(segments, event.getTask());
				}

				// TASK RESERVED
				if (operation == Operation.RESERVED) {
					event.setEstimatedToC(tkResponse.getReport()
							.getEstimatedToC());
					event.setUpdateDate(new DateTime());
					event.setEventId(null);
					event.setDescription("Task reserved successfully. "
							+ tkResponse.getReport().getDescription());
					event.setRequestStatus(RequestStatus.Accepted);
					event.setTaskStatus(TaskStatus.Reserved);
					event.setResponseParameters(UtilsDeimos
							.getParameters(tkResponse));
					if (messages)
						System.out.println(event.getDescription());
					Notification.notifyReport(event);
					taskController.insertEvent(event);
					taskController.insertSegments(segments, event.getTask());
				}

				if (operation == Operation.STUDIED) {
					event.setEstimatedToC(tkResponse.getReport()
							.getEstimatedToC());
					event.setUpdateDate(new DateTime());
					event.setEventId(null);
					event.setDescription(tkResponse.getReport()
							.getDescription());
					event.setRequestStatus(RequestStatus.Accepted);
					event.setResponseParameters(UtilsDeimos
							.getParameters(tkResponse));
					if (messages)
						System.out.println(event.getDescription());
					Notification.notifyReport(event);
					taskController.insertEvent(event);
				}
			} else if (requestStatus == RequestStatus.Rejected) {
				event.setRequestStatus(RequestStatus.Rejected);
				if (operation == Operation.SUBMITTED
						|| operation == Operation.RESERVED) {
					event.setEstimatedToC(tkResponse.getReport()
							.getEstimatedToC());
					event.setUpdateDate(new DateTime());
					event.setEventId(null);
					event.setDescription(this.tkResponse.getReport()
							.getDescription());
					if (messages)
						System.out.println(event.getDescription());
					Notification.notifyReport(event);
					taskController.insertEvent(event);
				}
				if (operation == Operation.STUDIED) {
					event.setEstimatedToC(tkResponse.getReport()
							.getEstimatedToC());
					event.setUpdateDate(new DateTime());
					event.setEventId(null);
					event.setDescription(this.tkResponse.getReport()
							.getDescription());
					if (messages)
						System.out.println(event.getDescription());
					Notification.notifyReport(event);
					taskController.insertEvent(event);
				}
				if (operation == Operation.UPDATED) {
					event.setEstimatedToC(tkResponse.getReport()
							.getEstimatedToC());
					event.setUpdateDate(new DateTime());
					event.setEventId(null);
					event.setDescription(this.tkResponse.getReport()
							.getDescription());
					if (messages)
						System.out.println(event.getDescription());
					Notification.notifyReport(event);
					taskController.insertEvent(event);
				}
			}
		}
	}

	public void addTask(GetFeasibilityResponse response, OMElement element) {
		Task task = new Task();
		Event event = new Event();

		StatusReport report = response.getReport();
		task.setSensorId(request.getSensorID());
		task.setServiceType(response.getService());
		task.setTaskId(report.getTaskID());
		task.setTitle(report.getTitle());

		event.setRequestStatus(report.getRequestStatus());
		event.setTaskStatus(report.getTaskStatus());
		event.setDescription(report.getDescription());
		event.setUpdateDate(new Date());
		event.setEstimatedToC(report.getEstimatedToC());
		event.setRequestParameters(UtilsDeimos.getParameters(request));
		event.setResponseParameters(UtilsDeimos.getParameters(tkResponse));
		event.setMaxCloud(maxCloud);
		event.setFeasibilityStudy(report != null
				&& report.getRequestStatus() == RequestStatus.Accepted);
		event.setBeginDate(begin);
		event.setEndDate(end);
		event.setOperation(this.operation);
		if (acquisitionSuccess != null)
			event.setAcquisitionSuccess(acquisitionSuccess.isAvailable());
		task.addEvent(event);
		taskController.insertTask(task);
	}

	public static void enableMessages(boolean enable) {
		messages = enable;
	}

}
